package common

import (
	"crypto/rand"
	"encoding/hex"
	mrand "math/rand"
	"sync"
	"time"
)

type randImpl struct {
	rnd  *mrand.Rand
	lock *sync.Mutex
}

var rndImpl *randImpl = newRandImpl()

func newRandImpl() *randImpl {
	return &randImpl{
		rnd:  mrand.New(mrand.NewSource(time.Now().UnixNano())),
		lock: &sync.Mutex{},
	}
}

func (this *randImpl) randInt(min int, max int) int {
	this.lock.Lock()
	defer this.lock.Unlock()

	if max == min {
		return max
	} else if max < min {
		t := max
		max = min
		min = t
	}
	x := max - min
	return min + this.rnd.Intn(x)
}

func (this *randImpl) randFloat64(min float64, max float64) float64 {
	this.lock.Lock()
	defer this.lock.Unlock()

	if max == min {
		return max
	} else if max < min {
		t := max
		max = min
		min = t
	}
	x := max - min
	return min + x*this.rnd.Float64()
}

func RandInt(min int, max int) int {
	return rndImpl.randInt(min, max)
}

func RandFloat64(min float64, max float64) float64 {
	return rndImpl.randFloat64(min, max)
}

func RandString(size int) string {
	buff := make([]byte, size)
	rand.Read(buff)
	return hex.EncodeToString(buff)
}

func RandBytes(size int) []byte {
	buff := make([]byte, size)
	rand.Read(buff)
	return buff
}
